package link

import (
	"TD-UI/internal/consts"
	"TD-UI/internal/model"
	"TD-UI/internal/model/entity"
	"TD-UI/internal/service"
	"context"
	"database/sql"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"log"
	"os"
	"path/filepath"
	"strconv"
	"sync"

	"github.com/gogf/gf/v2/crypto/gaes"
	"github.com/gogf/gf/v2/util/gconv"
	"github.com/google/uuid"
	_ "github.com/taosdata/driver-go/v3/taosRestful"
)

func init() {
	service.RegisterLink(New())
}

func New() service.ILink {
	return &sLink{}
}

type sLink struct{}

var cacheLinkConf []entity.Link

func OpenTasos(lid string, dbName string, cache bool) (*sql.DB, error) {
	// 获取缓存的链接
	var confList = make([]entity.Link, 0)
	decode := true
	if cache && cacheLinkConf != nil {
		confList = cacheLinkConf
		decode = false
	} else {
		confPath := loadLonkConfPath()
		content, err := os.ReadFile(confPath)
		if err != nil {
			panic(err)
		}
		conf := string(content)
		fmt.Println(conf)
		if conf != "" {
			json.Unmarshal([]byte(conf), &confList)
		}
	}

	var host, port, user, password string
	falg := false
	key := []byte(consts.AesKey)
	for i := 0; i < len(confList); i++ {
		if confList[i].Id == lid {
			host = confList[i].Host
			port = strconv.Itoa(confList[i].Port)
			user = confList[i].User
			if decode {
				pw, _ := hex.DecodeString(confList[i].Password)
				r, err := gaes.Decrypt(pw, key)
				if err != nil {
					panic(err)
				}
				password = string(r)
			} else {
				password = string(confList[i].Password)
			}

			falg = true
			break
		}
	}

	if !falg {
		panic("链接不存在")
	}

	var taosUri = fmt.Sprintf("%s:%s@http(%s:%s)/%s", user, password, host, port, dbName)
	log.Println(taosUri)
	taos, err := sql.Open("taosRestful", taosUri)
	if err != nil {
		log.Println("failed to connect TDengine, err:", err)
	}
	return taos, err
}

func (s *sLink) Link(ctx context.Context, req model.LinkReq) (res model.LinkRes, err error) {
	log.Print("------------------")
	taos, err := OpenTasos(req.Linkid, "", true)
	if err != nil {
		log.Println("failed to connect TDengine, err:", err)
	}
	defer taos.Close()

	result, err := taos.Query("SHOW DATABASES")
	if err != nil {
		return
	}
	defer result.Close()
	var dbs = make([]string, 0)
	for result.Next() {
		var dbName string
		err = result.Scan(&dbName)
		if err != nil {
			log.Println("failed to scan result, err:", err)
		}
		log.Println(dbName)
		dbs = append(dbs, dbName)
	}
	log.Println(dbs)
	res.Result = dbs
	return
}

func (s *sLink) Add(ctx context.Context, req model.LinkAddReq) (res model.LinkRes, err error) {
	data := entity.Link{}
	wg := sync.WaitGroup{}
	wg.Add(1)
	key := []byte(consts.AesKey)
	pw := []byte(req.Password)
	r, err := gaes.Encrypt(pw, key)
	pwd := hex.EncodeToString(r)
	err = gconv.Struct(req, &data)
	if err != nil {
		panic(err)
	}
	uid, _ := uuid.NewUUID()
	data.Id = uid.String()
	data.Password = pwd

	jb, err := json.Marshal(data)
	if err != nil {
		panic(err)
	}

	confJson := string(jb)
	log.Print(confJson)

	confPath := loadLonkConfPath()
	content, err := os.ReadFile(confPath)
	conf := string(content)
	file, err := loadLinkConf(confPath)
	if err != nil {
		panic(err)
	}
	defer file.Close()
	fmt.Println(conf)
	var confList = make([]entity.Link, 0)
	if conf != "" {
		json.Unmarshal([]byte(conf), &confList)
	}
	confList = append(confList, data)

	pj, err := json.Marshal(confList)
	log.Println(string(pj))
	file.WriteString(string(pj))
	return
}

func (s *sLink) GetAll(ctx context.Context, req model.LinkGetReq) (res model.LinkRes, err error) {
	confPath := loadLonkConfPath()
	content, err := os.ReadFile(confPath)
	conf := string(content)
	var confList = make([]entity.Link, 0)
	log.Println(conf)
	json.Unmarshal([]byte(conf), &confList)
	key := []byte(consts.AesKey)
	for i := 0; i < len(confList); i++ {
		fmt.Printf("%v\n", confList[i])
		pw, _ := hex.DecodeString(confList[i].Password)
		r, err := gaes.Decrypt(pw, key)
		if err != nil {
			panic(err)
		}
		confList[i].Password = string(r)
	}

	res.Result = confList
	cacheLinkConf = confList
	return
}

func (s *sLink) Del(ctx context.Context, req model.LinkDelReq) (err error) {
	confPath := loadLonkConfPath()
	content, err := os.ReadFile(confPath)
	conf := string(content)
	file, err := loadLinkConf(confPath)
	if err != nil {
		panic(err)
	}
	defer file.Close()
	fmt.Println(conf)
	var confList = make([]entity.Link, 0)
	if conf != "" {
		json.Unmarshal([]byte(conf), &confList)
	}

	for i := 0; i < len(confList); i++ {
		if confList[i].Id == req.LinkId {
			confList = append(confList[:i], confList[i+1:]...)
		}
	}

	pj, err := json.Marshal(confList)
	log.Println(string(pj))
	file.WriteString(string(pj))
	return
}

func loadLinkConf(path string) (file *os.File, err error) {
	file, err = os.OpenFile(path, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0644)
	return file, err
}

func loadLonkConfPath() string {
	absPath, err := filepath.Abs(".")
	if err != nil {
		panic("获取当前路径失败")
	}
	return absPath + string(os.PathSeparator) + consts.LinkConf
}
